package com.qk.management.aop;

import cn.hutool.json.JSONUtil;
import com.qk.common.Result;
import com.qk.common.util.CurrentUserContextHolders;
import com.qk.entity.OperateLog;
import com.qk.management.mapper.OperateLogMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

/**
 *
 * @author MrZhao
 * @created 2025-10-17 17:21
 * @description 定义日志记录切面
 * <p>
 * 增删改 操作 都记录日志表
 *
 */
@Slf4j
@Aspect
@Component
public class LogRecordAspect {

    @Autowired
    private OperateLogMapper operateLogMapper;

    // 定义切点
    @Pointcut("@annotation(com.qk.management.aop.anno.LogAnno)")
    public void pt() {
    }

    // 定义通知
    @Around("pt()")
    public Object log(ProceedingJoinPoint pjp) {
        // 定义目标方法的返回值
        Object returnValue = null;
        try {
            // 前
            long startTime = System.currentTimeMillis();
            // 执行切点方法/////////////////////////
            returnValue = pjp.proceed();
            /// //////////////////////////////////
            // 后
            long endTime = System.currentTimeMillis();
            // 获取操作人的Id
            Integer userId = CurrentUserContextHolders.get();
            // 获取执行类名称
            String className = pjp.getTarget().getClass().getName();
            // 获取执行方法名称
            String methodName = pjp.getSignature().getName();
            // 获取参数
            Object[] args = pjp.getArgs();
            // 工具类 hutool
            String params = JSONUtil.toJsonStr(args);
            // 获取返回值
            String result = JSONUtil.toJsonStr(returnValue);

            // 构造一个OperateLog对象
            OperateLog operateLog = OperateLog.builder()
                    .returnValue(result) // 返回值
                    .methodParams(params) // 参数
                    .methodName(methodName) // 方法名
                    .className(className) // 类名
                    .operateUserId(userId) // 操作人Id
                    .operateTime(LocalDateTime.now()) // 操作时间
                    .costTime(endTime - startTime) // 接口执行时间
                    .build();

            // 调用Mapper写入数据库
            // 记录日志成功与否不能影响正常业务执行！
            // 比如银行取钱 吐钞 + 打印凭条； 你不能因为打印凭条失败 就说取钱失败 因此 try catch
            try {
                operateLogMapper.insert(operateLog);
            } catch (Exception e) {
                log.error("操作日志写入数据库失败:{}", e.getMessage());
            }
        } catch (Throwable e) {
            returnValue = Result.error("您的操作失败，请稍后重试！");
            log.error("操作失败:{}", e.getMessage());
        }
        return returnValue;
    }


}
